package yape_jvm.yape.java.euler324;

/**
 * Represents a single layer in the tower. Methods are provided to help
 * determine block usage.
 */
public class GridLevel {
	/**
	 * The width of the grid.
	 */
	public static final int GRID_WIDTH = 3;

	/**
	 * The height of the grid.
	 */
	public static final int GRID_HEIGHT = 3;

	/**
	 * The total number of blocks in the grid.
	 */
	public static final int NUM_BLOCKS = GRID_WIDTH * GRID_HEIGHT;

	/**
	 * The block usage pattern.
	 */
	private int blocks;

	/**
	 * Create a new level with the given state (block fill pattern).
	 * 
	 * @param state
	 *            An integer where the nth bit indicates if the nth block is
	 *            used.
	 */
	public GridLevel(int state) {
		blocks = state;
	}

	/**
	 * Get all the blocks.
	 * 
	 * @return An integer where the first NUM_BLOCKS bits represent the blocks.
	 */
	public int getBlocks() {
		return blocks;
	}

	/**
	 * Return the status of the nth block.
	 * 
	 * @param n
	 *            The block number (from 0 to NUM_BLOCKS-1 inclusive)
	 * @return true if the block is empty; false if it's used.
	 */
	public boolean isBlockFree(int n) {
		return (blocks & (1 << n)) == 0;
	}

	/**
	 * Set the status of the nth block to "used".
	 * 
	 * @param n
	 *            The block to occupy.
	 */
	public void useBlock(int n) {
		blocks = blocks | (1 << n);
	}

	/**
	 * Get the first free block.
	 * 
	 * @return The number of the first free block, or -1 if all are full.
	 */
	public int getFirstOpenBlock() {
		for (int i = 0; i < NUM_BLOCKS; i++)
			if (isBlockFree(i))
				return i;

		return -1;
	}

	/**
	 * Determine if the block to the right of the given block is free (empty).
	 * 
	 * @param block
	 *            One of the blocks (0 - NUM_BLOCKS-1)
	 * @return true if free, false otherwise.
	 */
	public boolean isFreeToRightOf(int block) {
		int nextBlock = block + 1;
		if (nextBlock % GRID_WIDTH == 0)
			return false;
		else
			return isBlockFree(nextBlock);
	}

	/**
	 * Determine if the block directly below the given block is free (empty).
	 * 
	 * @param block
	 *            One of the blocks (0 - NUM_BLOCKS-1)
	 * @return true if free; false otherwise.
	 */
	public boolean isFreeBelow(int block) {
		int nextBlock = block + GRID_WIDTH;
		if (nextBlock >= NUM_BLOCKS)
			return false;
		else
			return isBlockFree(nextBlock);
	}
}
